﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using LLoger;
using OpenPop.Mime;
using TSRepLoader.Pop;
using TSRepLoader.Properties;
using OpenPop.Mime.Header;

namespace TSRepLoader
{

    [Serializable]
    public class HandelAttacmentException : Exception
    {
        //
        // For guidelines regarding the creation of new exception types, see
        //    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
        // and
        //    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
        //

        public HandelAttacmentException()
        {
        }

        public HandelAttacmentException(string message)
            : base(message)
        {
        }

        public HandelAttacmentException(string message, Exception inner)
            : base(message, inner)
        {
        }

        protected HandelAttacmentException(
            SerializationInfo info,
            StreamingContext context)
            : base(info, context)
        {
        }
    }

    /// <summary>
    /// Загрузка писем и складирование Аттачей в указанное место, с их последующей обработкой (если необходимо)
    /// </summary>
    public abstract class MailDownloader : IDisposable
    {

        private readonly string _host;
        private readonly int _port;
        private readonly bool _ssl;
        private readonly string _user;
        private readonly string _pass;
        private PopWrapper _popClient;
        protected readonly ILogWriter _log;
        private Settings _sett = Properties.Settings.Default;
        private DateTime _loadDate;
        private int _loadDepth = 20;

        /// <summary>
        /// путь для работы с отчетами
        /// </summary>
        protected virtual string RootDestinationFolder
        {
            get { return _sett.DestFolder; }
        }

        /// <summary>
        /// Путь сохранения вложений
        /// </summary>
        protected virtual string DownloadFolder
        {
            get { return _sett.DownloadPath; }
        }

        protected DateTime LoadDate
        {
            get { return _loadDate; }
        }

        /// <summary>
        /// Установка Глубины загрузки писем. ОТ самых новых до -val
        /// </summary>
        /// <param name="val"></param>
        public void SetLoadDepth(int val)
        {
            _loadDepth = val;
        }

        public MailDownloader(string host, int port, bool ssl, string user, string pass, ILogWriter log)
        {
            _host = host;
            _port = port;
            _ssl = ssl;
            _user = user;
            _pass = pass;
            _log = log ?? new DummyLog();
            _popClient = new PopWrapper(_host, _port, _ssl, _user, _pass, _log);
        }

        public virtual void Load()
        {
            Load(DateTime.Today);
        }

        public virtual void Load(DateTime date)
        {
            Load(date, null, null, null);
        }

        protected void CheckAndCreatePath(string path)
        {
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
        }

        public void Load(DateTime date, string from, string subj, string msgId)
        {
            _loadDate = date;

            CheckAndCreatePath(RootDestinationFolder);
            CheckAndCreatePath(DownloadFolder);


            _log.WriteLine("----------------------------------------------------------");
            _log.WriteLine("Download mails for " + date.ToString("dd.MM.yyyy HH:mm:ss") + " from " + _host);
            //Найти нужные письма

            var messageList = _popClient.FindMsg(date, from, subj, msgId, _loadDepth);

            if (messageList == null)
            {
                _log.WriteLine("WARNING: There are no mails");
                return;
            }

            _log.WriteLine(messageList.Count() + " message(s) found");
            foreach (var message in messageList)
            {
                // для каждого письма извлечь вложения
                var att = message.FindAllAttachments();
                if (att == null || att.Count == 0)
                {
                    _log.WriteLine("WARNING: Mail {0} doesn't contains any attachment", message.Headers.Subject);
                    continue;
                }

                _log.WriteLine(att.Count + " attachment(s) found\r\nSave the mail attachments...");
                // сохранить и обаботать все вложения письма
                if (!SaveAttachments(att, message.Headers))
                {
                    _log.WriteLine("WARNING: Some trouble happend with attachments");
                    continue;
                }
            }
        }


        private bool SaveAttachments(List<MessagePart> att, MessageHeader msgHdr = null)
        {
            bool res = false;
            foreach (var a in att)
                try
                {
                    // сохранить вложение и получить путь к сохраненному файлу
                    string savedFile = SaveToFile(a, msgHdr);
                    if (!string.IsNullOrWhiteSpace(savedFile))
                    {
                        _log.WriteLine("A new attachment " + a.FileName + " was saved to " + savedFile);
                        _log.WriteLine("Additional Handle of attachment...");

                        // при успешном сохраниении обработать вложение, если надо (разархивировать, расшифровать)
                        if (!HandleAttachment(savedFile, msgHdr))
                            _log.WriteLine("WARNING: Unable to handle an attachment " + savedFile);

                        res = true;
                    }
                }
                catch (Exception ex)
                {
                    _log.WriteLine(ex, "ERROR: An error occured while saving the file");
                }

            return res;
        }

        protected abstract bool HandleAttachment(string savedFile, MessageHeader subject = null);

        protected abstract string SaveToFile(MessagePart attachment, MessageHeader subject = null);

        public void Dispose()
        {
            if (_popClient != null)
                _popClient.Dispose();
        }
    }
}
